#include "Uart.h"
#include <sys/select.h>
#include <sys/file.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "Utils.h"

Uart::Uart()
{
	m_fd = -1;
	m_bOpen = false;
	m_Th = 0;
	m_pOnRecv = NULL;
}

Uart::~Uart()
{
	Close();
}

bool Uart::Open(const char* path, int baud)
{
	Close();

	m_fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
	if (-1 == m_fd) {
		return false;
	}

	struct termios term;
	memset(&term, 0, sizeof(struct termios));
	term.c_cflag = CS8 | CREAD | CLOCAL | HUPCL;

	cfsetispeed(&term, baud);
	cfsetospeed(&term, baud);

	tcflush(m_fd, TCIOFLUSH);
	tcsetattr(m_fd, TCSANOW, &term);

	pthread_create(&m_Th, NULL, Proc, this);

	if (BeT()) {
		m_bOpen = true;
	}

	return m_bOpen;
}

void Uart::Close()
{
	m_bOpen = false;

	if (-1 != m_fd) {
		close(m_fd);
		m_fd = -1;
	}

	if (0 != m_Th) {
		m_Th = 0;
	}
}

void Uart::SetOnRecv(IOnRecv* pOnRecv)
{
	m_pOnRecv = pOnRecv;
}

bool Uart::BeT()
{
	return true;
}

void* Uart::Proc(void* lpParam)
{
	return ((Uart *)lpParam)->Func();
}

int Uart::Write(const byte* pData, int nLength)
{

	fd_set wfds;
	FD_ZERO(&wfds);
	FD_SET(m_fd, &wfds);

	timeval tv;
	tv.tv_sec  = 1;
	tv.tv_usec = 0;

	int ret = select(m_fd + 1, NULL, &wfds, NULL, &tv);

	switch (ret)
	{
		default:
			if (FD_ISSET(m_fd, &wfds)) {
				ret = write(m_fd, pData, nLength);
			} else {
				ret = 0;
			}
			break;
	}

	return ret;
}

bool Uart::IsOpen()
{
	return m_bOpen;
}

void* Uart::Func()
{
	while (m_bOpen)
	{
		fd_set rfds;
		FD_ZERO(&rfds);
		FD_SET(m_fd, &rfds);

		timeval tv;
		tv.tv_sec  = 0;
		tv.tv_usec = 200*1000;

		int ret = select(m_fd + 1, &rfds, NULL, NULL, &tv);

		switch (ret)
		{
		default:
			if (FD_ISSET(m_fd, &rfds)) {
				ret = read(m_fd, (char*)m_RecvBuf, 2000);

			if (ret > 0) {
				m_pOnRecv->OnRecv(m_RecvBuf, ret);

			}
			}
			break;
		}
	}

	return NULL;
}
